//
//  SpeechManager.swift
//  GLUZSwift
//
//  Created by xyanl on 2025/5/12.
//

import UIKit
import Speech
import NaturalLanguage

/// 标点预测模式
enum PunctuationMode {
    case none       // 不添加标点
    case basic      // 基础规则
    case nlp        // NaturalLanguage框架（iOS15+）
    case mlModel    // CoreML模型
}

/// 语音识别错误类型
enum SpeechError: Error, LocalizedError {
    case unsupportedLanguage    // 不支持的语言
    case permissionDenied       // 权限被拒绝
    case recognizerNotConfigured // 识别器未配置
    case audioFileReadError     // 音频文件读取错误
    
    var errorDescription: String? {
        switch self {
        case .unsupportedLanguage:
            return "当前设备不支持该语言"
        case .permissionDenied:
            return "没有语音识别权限，请前往设置开启"
        case .recognizerNotConfigured:
            return "语音识别器未正确配置"
        case .audioFileReadError:
            return "无法读取音频文件"
        }
    }
}

/// 语音识别支持的语言类型
///
/// - 预定义类型：包含常用语言的标准化代码
/// - 自定义类型：支持任意有效的语言标识符
enum SpeechRecognitionLanguage: Equatable {
    case zh      // 简体中文 (zh-CN)
    case en      // 美式英语 (en-US)
    case ru      // 俄语 (ru-RU)
    case custom(String)  // 自定义语言代码
    
    /// 获取标准的语言标识符字符串
    var identifier: String {
        switch self {
        case .zh: return "zh-CN"
        case .en: return "en-US"
        case .ru: return "ru-RU"
        case .custom(let code): return code
        }
    }
    
    /// 获取语言的本地化显示名称
    var localizedName: String {
        let locale = Locale(identifier: identifier)
        return locale.localizedString(forIdentifier: identifier) ?? identifier
    }
}


/// 语音识别管理器代理协议
protocol SpeechManagerDelegate: AnyObject {
    
    /// 识别完成回调
    /// - Parameters:
    ///   - text: 识别结果文本，失败时为空字符串
    ///   - isSuccess: 是否成功识别
    func didFinishRecognition(text: String, isSuccess: Bool, error: SpeechError?)
    
    /// 实时识别结果回调（当shouldReportPartialResults为true时触发）
    /// - Parameter text: 当前识别到的部分文本
    func didReceiveTranscription(text: String)
    
    /// 检测到不支持的语言时回调
    /// - Parameter language: 不支持的语言类型
    func didDetectUnsupportedLanguage(_ language: SpeechRecognitionLanguage)
    
}

/// 语音识别核心管理类
/// - 封装了iOS原生Speech框架的功能
/// - 提供文件语音识别和权限管理
/// - 支持多语言切换和实时识别
class SpeechManager: NSObject {
    
    // MARK: - 单例模式
    
    /// 共享实例（单例模式）
    static let shared = SpeechManager()
    /// 私有化初始化方法（强制单例）
    private override init() {
        super.init()
    }
    
    // MARK: - 属性
    
    /// 当前语音识别任务（用于取消等操作）
    private var recognitionTask: SFSpeechRecognitionTask?
    
    /// 语音识别器实例（与语言绑定）
    private var recognizer: SFSpeechRecognizer?
    
    /// 代理对象（使用weak避免循环引用）
    weak var delegate: SpeechManagerDelegate?
    
    /// 当前使用的识别语言（默认中文）
    private(set) var currentLanguage: SpeechRecognitionLanguage = .zh
    private var punctuationMode: PunctuationMode = .basic
    
    
    // MARK: - 公共方法
    
    /// 配置语音识别器, 可以的话,开始的时候初始话,尽量少切换语言
    /// - Parameter language: 语言代码，例如 "zh-CN" 简体中文, "en-US" 美式英语, "ru-RU" 俄语
    /// - Returns: true: 已经配置语音识别器
    func configure(language: SpeechRecognitionLanguage) -> Bool {
        
        // 检查语言是否被系统支持
        guard isLanguageSupported(language) else {
            // 通知代理语言不支持
            delegate?.didDetectUnsupportedLanguage(language)
            return false
        }
        
        // 是否已经配置过语音识别器
        if let recognizer = recognizer {
            // 已经配置过了
            if recognizer.locale.identifier != language.identifier {
                // 语言不相同,需要重新配置
                initSpeechRecognizer(language)
            }
        } else {
            // 还没有语音识别器,需要创建
            initSpeechRecognizer(language)
        }
        
        return true
    }
    
    
    /// 创建新的语音识别器实例
    /// - Parameter language: 本地化语言
    private func initSpeechRecognizer(_ language: SpeechRecognitionLanguage) {
        
        currentLanguage = language
        
        // 创建新的语音识别器实例
        recognizer = SFSpeechRecognizer(locale: Locale(identifier: language.identifier))
        
        // 设置专用队列处理识别结果（避免阻塞主线程）
        recognizer?.queue = OperationQueue()
        
        xLog("[语音识别] 已配置语言: \(language.identifier)")
        
    }
    
    /// 检查特定语言是否被当前设备支持
    /// - Parameter language: 要检查的语言类型
    /// - Returns: 返回布尔值表示是否支持
    func isLanguageSupported(_ language: SpeechRecognitionLanguage) -> Bool {
        // 获取系统支持的所有语言Locale
        let supportedLocales = SFSpeechRecognizer.supportedLocales()
        // 检查目标语言是否在支持列表中
        return supportedLocales.contains {
            $0.identifier == language.identifier
        }
    }
    
    
    /// 从音频文件识别语音
    /// - Parameters:
    ///   - fileURL: 音频文件URL
    ///   - language: 识别语言代码（可选，如果为nil则使用当前配置的语言）
    ///   - shouldReportPartialResults: 是否返回部分识别结果（实时识别）
    func recognizeFromAudioFile(
        fileURL: URL,
        language: SpeechRecognitionLanguage,
        shouldReportPartialResults: Bool = false
    ) {
        
        // 检查授权
        guard SFSpeechRecognizer.authorizationStatus() == .authorized else {
            xLog("[语音识别] 未授权语音识别")
            delegate?.didFinishRecognition(text: "", isSuccess: false, error: .permissionDenied)
            return
        }
        
        // 配置语音识别器
        if !configure(language: language) {
            return
        }
        
        // 创建语音识别请求
        let request = SFSpeechURLRecognitionRequest(url: fileURL)
        // 配置请求参数
        request.shouldReportPartialResults = shouldReportPartialResults
        // 是否使用设备端识别（iOS13+）
        request.requiresOnDeviceRecognition = false
        
        // 取消之前的识别任务（如果存在）
        recognitionTask?.cancel()
        recognitionTask = nil
        
        xLog("[语音识别] 开始识别文件: \(fileURL.lastPathComponent)")
        
        // 开始新的识别任务
        recognitionTask = recognizer?.recognitionTask(with: request, delegate: self)
    }
    
    /// 取消当前正在进行的识别任务
    func cancelRecognition() {
        recognitionTask?.cancel()
        recognitionTask = nil
        xLog("[语音识别] 已取消当前识别任务")
    }
    
    /// 请求语音识别权限（异步）
    /// - Parameter completion: 授权结果回调（主线程执行）
    func requestAuthorization(completion: @escaping (Bool) -> Void) {
        SFSpeechRecognizer.requestAuthorization { status in
            // 确保回调在主线程执行
            DispatchQueue.main.async {
                let authorized = status == .authorized
                xLog("[语音识别] 授权结果: \(authorized ? "成功" : "失败")")
                completion(authorized)
            }
        }
    }
    
}


// MARK: - SFSpeechRecognitionTaskDelegate
extension SpeechManager: SFSpeechRecognitionTaskDelegate {
    
    /// 收到实时识别结果
    func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didHypothesizeTranscription transcription: SFTranscription) {
        let text = transcription.formattedString
        xLog("[语音识别] 实时识别结果: \(text)")
        delegate?.didReceiveTranscription(text: text)
    }
    
    /// 识别完成
    func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishRecognition recognitionResult: SFSpeechRecognitionResult) {
        let text = recognitionResult.bestTranscription.formattedString
        xLog("[语音识别] 最终识别结果: \(text)")
        delegate?.didFinishRecognition(text: text, isSuccess: true, error: nil)
    }
    
    /// 识别任务完成（成功或失败）
    func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishSuccessfully successfully: Bool) {
        if !successfully {
            xLog("[语音识别] 识别失败")
            delegate?.didFinishRecognition(text: "", isSuccess: false, error: .audioFileReadError)
        }
        recognitionTask = nil
    }
}
